// 环形队列
#ifndef _Ring_QUEUE_HPP_ // 防止重复包含
#define _Ring_QUEUE_HPP_ // 如果此前未定义_Ring_QUEUE_HPP_，执行下列代码

#include <iostream>
#include <vector>
#include <pthread.h>
#include "sem.hpp"

const int g_default_num = 5; // 默认存储元素个数设为5

// 多线程
template<class T>
class RingQueue
{
public:
    // 构造
    RingQueue(int default_num = g_default_num)
        :_ring_queue(default_num),
        _num(default_num),
        c_step(0),
        p_step(0),
        _space_sem(default_num),
        _data_sem(0)
    {
        pthread_mutex_init(&clock, nullptr); // 初始化互斥锁
        pthread_mutex_init(&plock, nullptr);   
    }

    // 析构
    ~RingQueue()
    {
        pthread_mutex_destroy(&clock); // 销毁互斥锁
        pthread_mutex_destroy(&plock);
    }

    // 生产者进程: 将指定元素放入队列
    void push(const T& in)
    {
        // 先申请信号量
        _space_sem.p(); // 等待信号
        pthread_mutex_lock(&plock); // 加锁

        _ring_queue[p_step++] = in; // 生产数据: 将in给环形队列，生产者下标++
        p_step %= _num; // 实现环形结构

        pthread_mutex_unlock(&plock); // 解锁
        _data_sem.v(); // 销毁信号
    }

    // 消费者进程: 从队列中取出元素
    void pop(T* out)
    {
        // 多个消费者线程可能会竞争修改 c_step 的值
        // 通过互斥锁 保护对 c_step 的访问
        // 只有成功竞争到互斥锁的消费者线程才能修改 
        _data_sem.p();
        pthread_mutex_lock(&clock);
        *out = _ring_queue[c_step++]; // 
        c_step %= _num;
        
        pthread_mutex_unlock(&clock);
        _space_sem.v();
    }

private:
    std::vector<T> _ring_queue; // 物理结构: 数组
    int _num; // 当前元素个数
    int c_step; // 生产者下标
    int p_step; // 消费者下标

    Sem _space_sem; // 空间信号量，表示可用空闲缓冲区数
    Sem _data_sem; // 数据信号量，表示当前已生产的产品数
    pthread_mutex_t clock; // 互斥锁，用于保护 c_step 的访问
    pthread_mutex_t plock; // 互斥锁，用于保护 p_step 的访问
};

#endif